﻿
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs.LowLevel.Unsafe;
using Unity.Mathematics;

[BurstCompile]
public struct ThreadRandom
{
    [NativeDisableContainerSafetyRestriction]
    [NativeDisableUnsafePtrRestriction]
    [NativeDisableParallelForRestriction]
    NativeArray<uint> threadseed;

    public void Init(uint seed = 0x6E624EB7u)
    {
        var random = new Random();
        random.InitState(seed);

        //按照jobs 数量初始化种子
        threadseed = new NativeArray<uint>(JobsUtility.ThreadIndexCount, Allocator.Persistent);
        for (var i = 0; i < threadseed.Length; i++)
        {
            threadseed[i] = (random.NextUInt());
        }

    }

    //通常只在jobs 和 system 中调用是没有问题的
    //system和jobs 时间片完全错开。
    //目前测试的反应是 不在jobssystem中时 threadindex总是等于0
    //其它线程调用无非是种子错乱
    uint NextState()
    {
        var i = JobsUtility.ThreadIndex;

        //保护ID范围
        if (i < 0 || i >= threadseed.Length)
            i = 0;


        //修改随机数实现和Unity一致
        var state = threadseed[i];

        state ^= state << 13;
        state ^= state >> 17;
        state ^= state << 5;
        threadseed[i] = state;

        return state;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public float NextFloat()
    {
        return asfloat(0x3f800000 | (NextState() >> 9)) - 1.0f;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public float NextFloat(float min, float max) { return NextFloat() * (max - min) + min; }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public float NextFloat(float max) { return NextFloat() * max; }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public int NextInt()
    {
        return (int)NextState() ^ -2147483648;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public int NextInt(int max)
    {
        CheckNextIntMax(max);
        return (int)((NextState() * (ulong)max) >> 32);
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public int NextInt(int min, int max)
    {
        CheckNextIntMinMax(min, max);
        uint range = (uint)(max - min);
        return (int)(NextState() * (ulong)range >> 32) + min;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public uint NextUInt()
    {
        return NextState() - 1u;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public uint NextUInt(uint max)
    {
        return (uint)((NextState() * (ulong)max) >> 32);
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public uint NextUInt(uint min, uint max)
    {
        CheckNextUIntMinMax(min, max);
        uint range = max - min;
        return (uint)(NextState() * (ulong)range >> 32) + min;
    }
    [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
    private void CheckNextIntMax(int max)
    {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        if (max < 0)
            throw new System.ArgumentException("max must be positive");
#endif
    }
    [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
    private void CheckNextIntMinMax(int min, int max)
    {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        if (min > max)
            throw new System.ArgumentException("min must be less than or equal to max");
#endif
    }
    [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
    private void CheckNextUIntMinMax(uint min, uint max)
    {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        if (min > max)
            throw new System.ArgumentException("min must be less than or equal to max");
#endif
    }




    [StructLayout(LayoutKind.Explicit)]
    internal struct IntFloatUnion
    {
        [FieldOffset(0)]
        public int intValue;
        [FieldOffset(0)]
        public float floatValue;
    }
    static float asfloat(uint x)
    {
        IntFloatUnion u;
        u.floatValue = 0;
        u.intValue = (int)x;

        return u.floatValue;
    }
}
